package com.bestom.usbdevelop;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.InputFilter;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.githang.statusbar.StatusBarCompat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";
    public final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    private UsbManager usbManager;
    private Context mContext;
    private PendingIntent mPermissionIntent;
    private UsbDeviceConnection usbConnection;
    private UsbInterface usbInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        // 初始化UI
        initView();
        // 初始化类
        initData();
        registerReceiver(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {

        if (item.getItemId() == R.id.choice_device) {
            ArrayList<String> list = new ArrayList<>();
            final List<UsbDevice> deviceList = getDeviceList();
            for (UsbDevice device : deviceList) {
                list.add(device.getProductName());
            }
            final String[] items = list.toArray(new String[list.size()]);

            new AlertDialog.Builder(this)
                    .setTitle("Choice Device")
                    .setIcon(R.mipmap.ic_launcher)
                    .setItems(items, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            requestPermission(deviceList.get(i));
                        }
                    })
                    .show();
        }
        return super.onOptionsItemSelected(item);
    }

    private EditText id;
    private EditText blockCurrent;
    private EditText blockTime;
    private EditText runTime;
    private Spinner positions;
    private ScrollView scrollView;
    private TextView textView;

    private void initView() {
        Toolbar toolbar = findViewById(R.id.toolbar);
        toolbar.setTitle(getString(R.string.app_name));
        setSupportActionBar(toolbar);

        scrollView = findViewById(R.id.scrollView);
        textView = findViewById(R.id.textView);
        id = findViewById(R.id.id);
        id.setFilters(new InputFilter[]{new InputFilterMinMax(0, 65535)});
        positions = findViewById(R.id.positions);
        blockCurrent = findViewById(R.id.block_current);
        blockCurrent.setFilters(new InputFilter[]{new InputFilterMinMax(0, 255)});
        blockTime = findViewById(R.id.block_time);
        blockTime.setFilters(new InputFilter[]{new InputFilterMinMax(0, 255)});
        runTime = findViewById(R.id.run_time);
        runTime.setFilters(new InputFilter[]{new InputFilterMinMax(0, 65535)});
        findViewById(R.id.id_set).setOnClickListener(this);
        findViewById(R.id.id_query).setOnClickListener(this);
        findViewById(R.id.position_set).setOnClickListener(this);
        findViewById(R.id.block_current_set).setOnClickListener(this);
        findViewById(R.id.block_time_set).setOnClickListener(this);
        findViewById(R.id.run_time_set).setOnClickListener(this);
        findViewById(R.id.lock).setOnClickListener(this);
        findViewById(R.id.un_lock).setOnClickListener(this);
        findViewById(R.id.lock_status_query).setOnClickListener(this);
        findViewById(R.id.clear).setOnClickListener(this);
    }

    private DataTurn mDataTurn;
    private SharedPreferences mSharedPreferences;
    private void initData() {
        // 保存id信息
        mSharedPreferences = getSharedPreferences("SETTING", Context.MODE_PRIVATE);
        // 获取USB管理
        usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        // 数据转换工具
        mDataTurn = new DataTurn();
    }

    /**发送字符串数据转换成字节数组*/
    private byte[] hexToByteArr(String string, String dataCode, String dataSet){
        if (string.isEmpty()) return null;
        String hex = HexUtil.intToHex(string);
        // 计算校验和
        String checksum = HexUtil.makeChecksum(String.format(dataCode, hex));
        // 组合数据
        String format = String.format(dataSet, hex, checksum);
        return mDataTurn.HexToByteArr(format);
    }

    /**用于判断是否点击设置id*/
    private boolean isSetId;
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.id_set:
                isSetId = true;
                sendData(hexToByteArr(id.getText().toString(), HexStep.IDCode.getHexString(), HexStep.IDSet.getHexString()));
                updateView("request set id");
                break;
            case R.id.id_query:
                sendData(mDataTurn.HexToByteArr(HexStep.IDQuery.getHexString()));
                updateView("request query id");
                break;
            case R.id.position_set:
                if (positions.getSelectedItem().toString().equals("Positive")) {
                    sendData(mDataTurn.HexToByteArr(HexStep.PositionPositiveSet.getHexString()));
                    updateView("request set position to Positive");
                } else {
                    sendData(mDataTurn.HexToByteArr(HexStep.PositionInverseSet.getHexString()));
                    updateView("request set position to inverse");
                }
                break;
            case R.id.block_current_set:
                sendData(hexToByteArr(blockCurrent.getText().toString(), HexStep.BlockCurrentCode.getHexString(), HexStep.BlockCurrentSet.getHexString()));
                updateView("request set block current");
                break;
            case R.id.block_time_set:
                sendData(hexToByteArr(blockTime.getText().toString(), HexStep.BlockTimeCode.getHexString(), HexStep.BlockTimeSet.getHexString()));
                updateView("request set block time");
                break;
            case R.id.run_time_set:
                sendData(hexToByteArr(runTime.getText().toString(), HexStep.RunTimeCode.getHexString(), HexStep.RunTimeSet.getHexString()));
                updateView("request set run time");
                break;
            case R.id.lock:
                sendData(mDataTurn.HexToByteArr(HexStep.Lock.getHexString()));
                updateView("request lock");
                break;
            case R.id.un_lock:
                String id = mSharedPreferences.getString("id", "1234");
                if (id != null){
                    sendData(hexToByteArr(id, HexStep.UnLockCode.getHexString(), HexStep.UnLock.getHexString()));
                    updateView("request unlock");
                }else updateView("id is null");

                break;
            case R.id.lock_status_query:
                sendData(mDataTurn.HexToByteArr(HexStep.LockStatusQuery.getHexString()));
                updateView("request query lock status");
                break;
            case R.id.clear:
                textView.setText("");
                break;
            default:
                break;
        }
    }

    /**更新滚动框*/
    private void updateView(String info){
        if (!(usbConnection != null && usbEndpointOut != null)) info = "not connected to the USB, request fail";

        textView.append(info + "\n");
        scrollToBottom(scrollView,textView);
    }
    /**
     * 根据scrollView 和子view去测量滑动的位置
     */
    private void scrollToBottom(final ScrollView scrollView, final View view) {

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (scrollView == null || view == null) return;
                // offset偏移量。是指当textView中内容超出 scrollView的高度，那么超出部分就是偏移量
                int offset = view.getMeasuredHeight() - scrollView.getMeasuredHeight();
                if (offset < 0) offset = 0;
                //scrollview开始滚动
                scrollView.scrollTo(0, offset);
            }
        });
    }

    public List<UsbDevice> getDeviceList() {
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        List<UsbDevice> usbDevices = new ArrayList<>();
        while (deviceIterator.hasNext()) {
            UsbDevice device = deviceIterator.next();
            usbDevices.add(device);
        }
        return usbDevices;
    }

    /**
     * 判断对应 USB 设备是否有权限
     */
    public boolean hasPermission(UsbDevice device) {
        return usbManager.hasPermission(device);
    }

    /**
     * 请求获取指定 USB 设备的权限
     */
    public void requestPermission(UsbDevice device) {
        if (device != null) {
            if (usbManager.hasPermission(device)) {
                if (openPort(device) && readData.isInterrupted()) readData.start();
            } else {
                if (mPermissionIntent != null) {
                    usbManager.requestPermission(device, mPermissionIntent);
                    Toast.makeText(getApplicationContext(), "请求USB权限", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getApplicationContext(), "请注册USB广播", Toast.LENGTH_LONG).show();
                }
            }
        }
    }

    public void registerReceiver(Activity context) {
        mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        context.registerReceiver(usbReceiver, filter);
    }

    public BroadcastReceiver usbReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                // 获取权限结果的广播
                synchronized (this) {
                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device != null) {
                        //call method to set up device communication
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            if (openPort(device)) readData.start();
                        } else {
                            
                            updateView("Usb 获取权限失败!");
                            Log.e(TAG, device.getDeviceName() + "Usb 获取权限失败!");
                        }
                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                
                updateView("有新的设备插入了");
                // 有新的设备插入了，在这里一般会判断这个设备是不是我们想要的，是的话就去请求权限
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                // 有设备拔出了
                
                updateView("有设备拔出了");
            }
        }
    };

    public boolean openPort(UsbDevice device) {
        //获取设备接口，一般只有一个，多个的自己研究去
        Log.d(TAG, "device.getInterfaceCount()-->" + device.getInterfaceCount());
        for (int i = 0; i < device.getInterfaceCount(); i++){
            usbInterface = device.getInterface(i);
            //获取通讯连接端点数量
            int endpointCount = usbInterface.getEndpointCount();
            if (endpointCount < 2) continue;
            for (int j = 0; j < endpointCount; j++) {
                //遍历所有端点，找到输入端点与输出端点
                UsbEndpoint usbEndpoint = usbInterface.getEndpoint(j);
                if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                    //赋值输出端点
                    usbEndpointOut = usbEndpoint;
                } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                    //赋值输入端点
                    usbEndpointIn = usbEndpoint;
                }
            }
        }
        if (!(usbEndpointOut != null && usbEndpointIn != null)) {
            updateView("Usb 通信连接失败");
            return false;
        }

        // 判断是否有权限
        if (hasPermission(device)) {
            // 打开设备，获取 UsbDeviceConnection 对象，连接设备，用于后面的通讯
            usbConnection = usbManager.openDevice(device);

            if (usbConnection == null) {
                return false;
            }
            if (usbConnection.claimInterface(usbInterface, true)) {
                
                updateView("Usb 通信连接成功");
            } else {
                usbConnection.close();
                
                updateView("Usb 通信连接失败");
                return false;
            }
        } else {
            
            updateView("没有 USB 权限");
            return false;
        }

        return true;
    }

    private UsbEndpoint usbEndpointIn;
    private UsbEndpoint usbEndpointOut;



    private void sendData(byte[] bytes) {
        if (usbConnection != null && usbEndpointOut != null && bytes != null){
            
            usbConnection.bulkTransfer(usbEndpointOut, bytes, bytes.length, 500);
            if (isSetId) {
                // 设置id成功，保存id
                String string = id.getText().toString();
                mSharedPreferences.edit().putString("id",string).apply();
            }
        }
        if (isSetId) isSetId = false;
    }

    private byte[] mBytes = new byte[1024];
    private Thread readData = new Thread(new Runnable() {
        @Override
        public void run() {

            while (true) {

                // 循环接受数据的地方 , 只接受byte数据类型的数据
                if (usbConnection != null && usbEndpointIn != null) {
                    int i = usbConnection.bulkTransfer(usbEndpointIn, mBytes, mBytes.length, 3000);
                    if (i > 0) {
                        Message message = Message.obtain();
                        message.what = RECEIVER_MESSAGE_SUCCESS;
                        message.obj = mBytes;
                        mHandler.sendMessage(message);
                    } else {
                        try {
                            Thread.sleep(80);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Log.d(TAG, "in sleep 80 i--->" + i);
                    }
                }
            }
        }
    });

    /**
     * 使用handler将所有的操作统一到主线程
     * Handler相关判断的变量，对应：usb连接初始化成功、失败，usb连接接收消息成功、失败，usb连接发送消息成功、失败
     */
    private static final int RECEIVER_MESSAGE_SUCCESS = 1;
    private static final int SEND_MESSAGE_SUCCESS = 2;
    private static final int RECEIVER_MESSAGE_FAILED = 3;
    private static final int SEND_MESSAGE_FAILED = 4;

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case RECEIVER_MESSAGE_SUCCESS://成功接受到数据
                    String value = new String((byte[]) msg.obj);
                    updateView("成功接收到数据--->" + value);
                    break;
                case RECEIVER_MESSAGE_FAILED://接收消息失败
                    updateView("接收消息失败");
                    break;
                case SEND_MESSAGE_SUCCESS://发送数据成功
                    updateView("发送数据成功");
                    break;
                case SEND_MESSAGE_FAILED://发送数据失败
                    updateView("发送数据失败");
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideInput(v, ev)) {
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm != null) imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
            return super.dispatchTouchEvent(ev);
        }
        // 必不可少，否则所有的组件都不会有TouchEvent了
        if (getWindow().superDispatchTouchEvent(ev)) return true;
        return onTouchEvent(ev);
    }

    public boolean isShouldHideInput(View v, MotionEvent event) {
        if ((v instanceof EditText)) {
            int[] leftTop = {0, 0};
            //获取输入框当前的location位置
            v.getLocationInWindow(leftTop);
            int left = leftTop[0];
            int top = leftTop[1];
            int bottom = top + v.getHeight();
            int right = left + v.getWidth();
            // 点击的是输入框区域，保留点击EditText的事件
            return !(event.getX() > left) || !(event.getX() < right)
                    || !(event.getY() > top) || !(event.getY() < bottom);
        }
        return false;
    }

    private void close(){
        if (usbConnection != null) usbConnection = null;
        if (usbEndpointIn != null) usbEndpointIn = null;
        if (usbEndpointOut != null) usbEndpointOut = null;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        close();
        if (mHandler != null) mHandler = null;
    }
}